#include "Client.h"
#include "Config.h"
#include "PkgBufMgr.h"
#include "Iodp.h"
#include "ModMgr.h"
#include "Protocol.h"
#include "IpcPkgBuf.h"
#include "WorkSvr.h"

CClient::CClient()
{
    m_ifd = -1;
    m_tLast = 0;
    m_eProt = ProtType::Invalide;
    m_iMod = -1;
    m_bShake = false;
    m_ds = DataState::TypeParse;

    m_pssl = nullptr;
    m_pSvr = nullptr;
    m_pProt = nullptr;
    m_pbRecv = nullptr;
    m_pRecvBuf = nullptr;
    m_pSendBuf = nullptr;
    m_pIodp = nullptr;
    m_pClntInfo = nullptr;
}

CClient::~CClient()
{
    Destroy();
}

bool CClient::Init(int ifd, CWorkSvr *pSvr, SSL_CTX *ctxSvr, CBufMgr<> *pBufMgr)
{
    CPkgBufMgr *pbm = nullptr;

    if (0 >= ifd || nullptr == pSvr || nullptr == pBufMgr)
        return false;

    m_ifd = ifd;
    m_pSvr = pSvr;

    if (nullptr != ctxSvr)
    {
        m_pssl = SSL_new(ctxSvr);

        if (m_pssl == nullptr)
            return false;

        SSL_set_fd(m_pssl, ifd);
        SSL_set_accept_state(m_pssl);
    }

    m_pRecvBuf = pBufMgr->NewBuffer();

    if (nullptr == m_pRecvBuf)
    {
        Destroy();
        return false;
    }

    m_pSendBuf = pBufMgr->NewBuffer();

    if (nullptr == m_pSendBuf)
    {
        Destroy();
        return false;
    }

    pbm = CPkgBufMgr::GetInstance();

    if (nullptr == pbm)
    {
        Destroy();
        return false;
    }

    m_pbRecv = pbm->GetPkgBuf();

    if (nullptr == m_pbRecv)
    {
        Destroy();
        printf("Error m_pbRecv.Init:\tfile=%s\tline=%d\n", __FILE__, __LINE__);
        return false;
    }

    return true;
}

void CClient::Destroy()
{
    if (nullptr != m_pssl)
    {
        SSL_shutdown(m_pssl);
        SSL_free(m_pssl);
        m_pssl = nullptr;
    }

    if (-1 != m_ifd)
    {
        close(m_ifd);
        m_ifd = -1;
    }

    if (nullptr != m_pRecvBuf)
    {
        CBufMgr<> *pBufMgr = m_pRecvBuf->GetBufMgr();

        if (nullptr != pBufMgr)
        {
            pBufMgr->DeleteBuffer(m_pRecvBuf);
            m_pRecvBuf = nullptr;
        }
    }

    if (nullptr != m_pSendBuf)
    {
        CBufMgr<> *pBufMgr = m_pSendBuf->GetBufMgr();

        if (nullptr != pBufMgr)
        {
            pBufMgr->DeleteBuffer(m_pSendBuf);
            m_pSendBuf = nullptr;
        }
    }

    if (nullptr != m_pbRecv)
    {
        CPkgBufMgr *pbm = CPkgBufMgr::GetInstance();

        pbm->FreePkgBuf(m_pbRecv);
        m_pbRecv = nullptr;
    }

    if (nullptr != m_pProt)
    {
        delete m_pProt;
        m_pProt = nullptr;
    }

    if ((nullptr != m_pIodp) && (nullptr != m_pClntInfo))
    {
        m_pIodp->DeleteClient(m_pClntInfo);
        m_pIodp = nullptr;
    }
}

int CClient::HandShake()
{
    int iRet = -1;

    if (nullptr == m_pssl)
        return -1;

    iRet = SSL_accept(m_pssl); // 被动接收握手信息
    // iRet = SSL_do_handshake(m_pssl); // 主动发送握手信息

    // 握手未完成
    if (0 >= iRet)
    {
        iRet = SSL_get_error(m_pssl, iRet);

        // SSL握手出错
        if ((SSL_ERROR_WANT_READ != iRet) && (SSL_ERROR_WANT_WRITE != iRet))
        {
            printf("SSL_accept failed, error:%d\n", iRet);
            return -1;
        }
    }
    else
    {
        m_bShake = true;
    }

    return 0;
}

int CClient::Recv()
{
    int iRet = 0;

    if (nullptr == m_pRecvBuf)
        return -1;

    if (CConfig::bUseSsl && !m_bShake)
    {
        iRet = HandShake();

        // 处理与握手数据一起发来数据的情况
        if (m_bShake)
            iRet = m_pRecvBuf->Recv(m_ifd, m_pssl);
    }
    else
    {
        iRet = m_pRecvBuf->Recv(m_ifd, m_pssl);
    }

    return iRet;
}

int CClient::Read(void *pDest, int iLen)
{
    if (nullptr == m_pRecvBuf)
        return -1;

    return m_pRecvBuf->Read(pDest, iLen);
}

int CClient::Send()
{
    if (nullptr == m_pSendBuf)
        return -1;

    return m_pSendBuf->Send(m_ifd, m_pssl);
}

int CClient::SendPackage(void *pSrc, int iLen)
{
    if (nullptr == m_pSendBuf)
        return -1;

    return m_pSendBuf->Send(m_ifd, m_pssl, pSrc, iLen);
}

// 数据处理完毕后才调用本函数，m_pbRecv已处理完毕
int CClient::SendData(void *pSrc, int iLen)
{
    // 根据协议进行数据组包
    uint16_t nSize = m_pProt->PackageData(m_pbRecv->pBuffer, (uint8_t *)pSrc, iLen);

    if (0 == nSize)
        return -1;

    return m_pSendBuf->Send(m_ifd, m_pssl, m_pbRecv->pBuffer, nSize);
}

// 本实例通过IPC发送数据给其它客户端，异步调用，m_pbRecv可能正在使用，必须使用新的缓冲存储数据包
bool CClient::IpcSendDataExt(void *pSvr, CClient *pClnt, void *pSrc, int iLen)
{
    CPkgBufMgr *pbm = nullptr;
    PkgBuf *pbSend = nullptr;
    uint16_t nProtPkg = 0;
    uint16_t nTotal = 0;
    int iSent = -1;

    // IPC数据格式：1、长度(类型：uint16_t，值为后所有项的总长)
    // 2、IPC命令IpcCmd::SendData(类型：enum class:uint16_t)
    // 3、数据内容(CClient *) 4、需发送给客户端的数据
    uint16_t nIpcHead = sizeof(uint16_t) + sizeof(IpcCmd) + sizeof(CClient *);

    if (nullptr == pSvr || nullptr == pClnt || nullptr == pSrc || 0 >= iLen)
        return false;

    pbm = CPkgBufMgr::GetInstance();

    if (nullptr == pbm)
        return false;

    pbSend = pbm->GetPkgBuf();

    if (nullptr == pbSend)
        return false;

    nProtPkg = m_pProt->PackageData(pbSend->pBuffer + nIpcHead, (uint8_t *)pSrc, iLen);
    nTotal = nProtPkg + nIpcHead;
    *(uint16_t *)pbSend->pBuffer = nTotal - sizeof(uint16_t);
    *(IpcCmd *)(pbSend->pBuffer + sizeof(uint16_t)) = IpcCmd::SendData;
    *(CClient **)(pbSend->pBuffer + sizeof(uint16_t) + sizeof(IpcCmd)) = pClnt;

    iSent = ((CWorkSvr *)pSvr)->IpcSend(pbSend->pBuffer, nTotal);
    pbm->FreePkgBuf(pbSend);

    return (iSent == nTotal);
}

// 数据仅加IPC头数据，内部数据处理，不需要协议
bool CClient::IpcSendDataInt(void *pSvr, CClient *pClnt, void *pSrc, int iLen)
{
    int iSent = -1;
    uint16_t nTotal = 0;
    CPkgBufMgr *pbm = nullptr;
    PkgBuf *pbSend = nullptr;
    uint16_t nIpcHead = sizeof(uint16_t) + sizeof(IpcCmd) + sizeof(CClient *);

    if (nullptr == pSvr || nullptr == pClnt || nullptr == pSrc || 0 >= iLen)
    {
        printf("Error: IpcSendDataInt line=%d\n", __LINE__);
        return false;
    }

    pbm = CPkgBufMgr::GetInstance();

    if (nullptr == pbm)
    {
        printf("Error: IpcSendDataInt line=%d\n", __LINE__);
        return false;
    }

    pbSend = pbm->GetPkgBuf();

    if (nullptr == pbSend)
    {
        printf("Error: IpcSendDataInt line=%d\n", __LINE__);
        return false;
    }

    nTotal = nIpcHead + iLen;
    *(uint16_t *)pbSend->pBuffer = nTotal - sizeof(uint16_t);
    *(IpcCmd *)(pbSend->pBuffer + sizeof(uint16_t)) = IpcCmd::DataHandle;
    *(CClient **)(pbSend->pBuffer + sizeof(uint16_t) + sizeof(IpcCmd)) = pClnt;
    memcpy(pbSend->pBuffer + nIpcHead, pSrc, iLen);

    iSent = ((CWorkSvr *)pSvr)->IpcSend(pbSend->pBuffer, nTotal);
    pbm->FreePkgBuf(pbSend);

    return (iSent == nTotal);
}

// 数据处理，步骤如下
// 1、协议解析后组合成一个完整包
// 2、数据的业务处理
// 3、处理完毕，发结果数据回客户端
HandleResult CClient::DataHandle()
{
    HandleResult hr = HandleResult::Error;

    switch (m_ds)
    {
    case DataState::TypeParse:
        // 解析协议类型，协议握手
        if (ProtType::Invalide == m_eProt)
            hr = ProtTypeParse();
        break;

    case DataState::ModuleParse:
        // 解析所属业务模块
        if (-1 == m_iMod)
            hr = ModuleParse();
        break;

    case DataState::DataParse:
        // TODO: 数据包太长的情况下，解析为多包数据
        // 根据协议解析出纯业务数据的数据包
        hr = DataProcess();
        break;

    default:
        break;
    }

    return hr;
}

// IPC客户端实例间的通讯，仅有IPC头，pSrc为纯数据（数据处理模块中的cmd+数据）
bool CClient::IpcDataHandle(void *pSrc, int iLen)
{
    // 传递数据给模块处理
    bool bRet = m_pIodp->DataHandle(m_pClntInfo, (uint8_t *)pSrc, iLen);

    if (!bRet)
        printf("Error: IPC m_pIodp->DataHandle\n");

    return bRet;
}

HandleResult CClient::ProtTypeParse()
{
    ProtModule pm;
    HandleResult hr = HandleResult::Fail;

    if (nullptr != m_pProt)
    {
        printf("Error: ProtTypeParse line=%d", __LINE__);
        return HandleResult::Error;
    }

    m_pProt = CProtocol::ProtParse(m_pRecvBuf, m_pbRecv, pm);

    if (nullptr == m_pProt)
        return HandleResult::Fail;

    if (ProtType::Invalide != pm.pt)
    {
        m_eProt = pm.pt;
        m_ds = DataState::ModuleParse;
    }

    if (-1 != pm.iMod)
    {
        m_iMod = pm.iMod;
        m_pIodp = GetIodp(pm.iMod);

        if (nullptr == m_pIodp)
        {
            // 错误处理
            printf("Error: get iodp module\n");
            return HandleResult::Error;
        }

        m_ds = DataState::DataParse;
    }

    if (DataState::ModuleParse == m_ds || DataState::DataParse == m_ds)
    {
        // 创建协议对象
        // if (nullptr == m_pProt)
        // {
        // m_pProt = CProtocol::CreateProtocol(pm.pt);

        // if (nullptr == m_pProt)
        //     return HandleResult::Error;

        // 发送协议握手成功信息回客户端
        if (m_pProt->ProtResponse(m_pbRecv, true))
        {
            int iSent = SendPackage(m_pbRecv->pBuffer, m_pbRecv->nPkgLen);

            if (-1 == iSent)
                return HandleResult::Error;

            // 通知模块添加新客户端
            m_pClntInfo = m_pIodp->NewClient(m_pSvr, this);

            if (nullptr == m_pClntInfo)
                return HandleResult::Error;
        }
        // }

        hr = HandleResult::Success;
    }

    m_pbRecv->Reset();

    return hr;
}

HandleResult CClient::ModuleParse()
{
    HandleResult hr = HandleResult::Fail;
    int8_t iMod = m_pProt->ModuleParse(m_pRecvBuf, m_pbRecv);

    if (0 <= iMod)
    {
        bool bRet = false;

        m_iMod = iMod;
        m_pIodp = GetIodp(iMod);

        if (nullptr == m_pIodp)
        {
            // 错误处理
            printf("Error: get iodp module\n");
            return HandleResult::Error;
        }

        bRet = m_pProt->ModuleResponse(m_pbRecv, true);

        if (bRet)
        {
            // 发送已处理模块信息
            int iSent = SendPackage(m_pbRecv->pBuffer, m_pbRecv->nPkgLen);

            if (-1 == iSent)
                return HandleResult::Error;

            // 向模块添加新客户端
            m_pClntInfo = m_pIodp->NewClient(m_pSvr, this);

            if (nullptr == m_pClntInfo)
                return HandleResult::Error;

            hr = HandleResult::Success;
        }

        m_ds = DataState::DataParse;
        m_pbRecv->Reset();
    }

    return hr;
}

HandleResult CClient::DataProcess()
{
    HandleResult hr = m_pProt->DataParse(m_pRecvBuf, m_pbRecv);

    if (HandleResult::Success == hr)
    {
        hr = m_pProt->DataHandle(m_pbRecv, this);

        // 去除数据已被协议处理的情况
        if ((HandleResult::Fail == hr) && (0 < m_pbRecv->nPkgLen))
        {
            // 传递数据给模块处理,m_pbRecv->pBuffer为纯数据，不包含长度
            bool bRet = m_pIodp->DataHandle(m_pClntInfo, m_pbRecv->pBuffer, m_pbRecv->nPkgLen);

            if (!bRet)
            {
                printf("Error: m_pIodp->DataHandle\n");
                return HandleResult::Error;
            }

            hr = HandleResult::Success;
        }

        m_pbRecv->Reset();
    }

    return hr;
}

CIodp *CClient::GetIodp(int8_t iMod)
{
    CModMgr *pModMgr = CModMgr::GetInstance();

    if (nullptr == pModMgr)
        return nullptr;

    return pModMgr->GetIodp(iMod);
}